"""
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    created by lei.chang on '23/04/2023'
    comment: 微服务(内部)
"""
import io
import aiohttp
from starlette.datastructures import UploadFile
from aiohttp import FormData
from project.core.exception import BizError
from project.lib.common import logger


class MicroService:
    """ 微服务(内部)
    """
    def __init__(self, domain, headers=None):
        """
        """
        self.domain = domain
        self.headers = {
            'Content-Type': 'application/json'
        }
        if headers is not None:
            self.headers.update(headers)

    async def get(self, url_path, **kwargs):
        """
        :param url_path:
        :param kwargs:
        :return:
        """
        url = f'{self.domain}{url_path}'

        async with aiohttp.ClientSession() as session:
            async with session.get(url, headers=self.headers, params=kwargs) as resp:
                if resp.status != 200:
                    raise BizError(f'AIS服务接口请求失败 status: {resp.status} url: {url} 参数信息: {kwargs}')

                result = await resp.json()
                if result.get('code') != 0:
                    logger.critical(f'{result.get("message", "")}, url: {url} 参数信息: {kwargs}')
                    raise BizError(code=result.get('code'), message=result.get("message", ""))

        return result.get('data', {})

    async def post(self, url_path, **kwargs):
        """
        :param url_path:
        :param kwargs:
        :return:
        """
        url = f'{self.domain}{url_path}'

        async with aiohttp.ClientSession() as session:
            async with session.post(url, headers=self.headers, json=kwargs) as resp:
                if resp.status != 200:
                    raise BizError(f'AIS服务接口请求失败 status: {resp.status} url: {url}')

                result = await resp.json()
                if result.get('code') != 0:
                    logger.critical(f'{result.get("message", "")}, url: {url} 参数信息: {kwargs}')
                    raise BizError(code=result.get('code'), message=result.get("message", ""))

        return result.get('data', {})

    async def post_streaming(self, url_path, **kwargs):
        """ 流式
        :param url_path:
        :param kwargs:
        :return:
        """
        url = f'{self.domain}{url_path}'

        async with aiohttp.ClientSession() as session:
            async with session.post(url, headers=self.headers, json=kwargs) as resp:
                while True:
                    data = await resp.content.read(1024)
                    if not data:
                        break

                    try:
                        yield data.decode('utf-8')
                    except UnicodeDecodeError:
                        continue

    async def post_form_data(self, url_path, **kwargs):
        """ 上传表单数据
        :param url_path:
        :param kwargs:
        :param kwargs:
        :return:
        """
        url = f'{self.domain}{url_path}'
        form_data = FormData()
        for key, value in kwargs.items():
            if isinstance(value, str):
                form_data.add_field(key, value)
            elif isinstance(value, UploadFile):
                form_data.add_field(key, io.BytesIO(await value.read()), filename=value.filename)
            elif isinstance(value, list):
                for v in value:
                    if not isinstance(v, UploadFile):
                        continue
                    form_data.add_field(key, io.BytesIO(await v.read()), filename=v.filename)

        async with aiohttp.ClientSession() as session:
            async with session.post(url, data=form_data) as resp:
                if resp.status != 200:
                    raise BizError(f'AIS服务接口请求失败 status: {resp.status} url: {url}')

                result = await resp.json()
                if result.get('code') != 0:
                    logger.critical(f'{result.get("message", "")}, url: {url} 参数信息: {kwargs}')
                    raise BizError(code=result.get('code'), message=result.get("message", ""))

        return result.get('data', {})
